#pragma once
#include<iostream>
using namespace std;
#include<pthread.h>
#include<queue>
#include<cstdlib>
#include<ctime>
#define NUM 10
template<class T>
class blockingqueue
{
  bool isFull()
  {
    return q.size()==cap;
  }
  bool isEmpty()
  {
    return q.size()==0;
  }
  public:
    blockingqueue(int _cap=NUM)
      :cap(_cap)
    {
      pthread_mutex_init(&lock,NULL);
      pthread_cond_init(&full,NULL);
      pthread_cond_init(&empty,NULL);
    }
    void Push(T& in)
    {
      pthread_mutex_lock(&lock);
      while(isFull())
      {
        //wait是函数可能失败，造成伪唤醒，
        //所以通过while循环再次进行判定
        //队列为空不能push等待消费者Pop
        pthread_cond_wait(&full,&lock);
      }
      q.push(in);
      pthread_mutex_unlock(&lock);
      if(q.size()>=cap/2)
      {
        cout<<"数据太多了，消费者来消费吧"<<endl;
        pthread_cond_signal(&empty);
      }
    }
    void Pop(T& out)
    {
      pthread_mutex_lock(&lock);
      while(isEmpty())
      {
        pthread_cond_wait(&empty,&lock);
      }
      out=q.front();
      q.pop();
      pthread_mutex_unlock(&lock);
      if(q.size()<=cap/2)
      {
        cout<<"数据已经快不够了，生产者来生产吧"<<endl;
        pthread_cond_signal(&full);
        
      }
    }
    ~blockingqueue()
    {
      pthread_mutex_destroy(&lock);
      pthread_cond_destroy(&full);
      pthread_cond_destroy(&empty);        
    }
  public:
    queue<T> q;
  private:
    int cap;
    pthread_mutex_t lock;
    pthread_cond_t full;
    pthread_cond_t empty;
};
